import { computed, readonly, ref } from 'vue'
import { usePrevious, useSwipe as useVueuseSwipe } from '@vueuse/core'
import velocityCalculator from '@/utils/velocity-calculator'

const { abs, floor } = Math

export function useSwipe(
  targetRef,
  {
    isVertical = false,
    startThreshold = 0,
    velocityThreshold = 100,
    viewLength,
    edgeDist = 0,
    onBackward,
    onForward,
    onRevert,
    onBackwardBlock,
    onForwardBlock,
    onReverseSwipe,
    isBlockBackward = () => false,
    isBlockForward = () => false,
  },
) {
  let swipeStart = false
  let swipeStartDirection = null
  const DIRS = isVertical ? ['up', 'down'] : ['left', 'right']
  const VIEW_LENGTH = viewLength || window[isVertical ? 'innerHeight' : 'innerWidth']
  const { reset, updatePosition, getVelocity } = velocityCalculator()

  const offset = ref(0)
  const swiping = computed(() => offset.value !== 0)
  const transitionDuration = ref(null)
  const setTransDur = (v) => (transitionDuration.value = v ? `${v * 0.25}s` : null)

  const { direction, lengthX, lengthY, coordsStart } = useVueuseSwipe(targetRef, {
    threshold: startThreshold,
    onSwipe(evt) {
      if (!swipeStartDirection && direction.value !== 'none') {
        swipeStartDirection = direction.value
      }

      // 起始滑動方向與初始設定不同則不處理
      if (!DIRS.includes(swipeStartDirection)) {
        onReverseSwipe && onReverseSwipe(evt, swipeStartDirection)
        return
      }

      // 起始滑動位置不在範圍內則不處裡
      if (edgeDist > 0) {
        const startPos = coordsStart[isVertical ? 'y' : 'x']
        if (startPos <= edgeDist || startPos >= VIEW_LENGTH - edgeDist) {
          return
        }
      }

      const length = floor(isVertical ? lengthY.value : lengthX.value)

      // 往前滑，第一個或被鎖住
      if (length < 0 && isBlockBackward()) {
        return
      }

      // 往後滑，最後一個或被鎖住
      if (length > 0 && isBlockForward()) {
        return
      }

      evt.stopPropagation()

      if (!swipeStart) {
        swipeStart = true
      }

      offset.value = length
      updatePosition(length)
    },
    onSwipeEnd(evt) {
      const dir = swipeStartDirection
      swipeStartDirection = null

      const length = floor(isVertical ? lengthY.value : lengthX.value)

      if (!swipeStart) {
        if (DIRS.includes(dir)) {
          if (length < 0 && onBackwardBlock) {
            onBackwardBlock()
          }
          if (length > 0 && onForwardBlock) {
            onForwardBlock()
          }
        }
        return
      }

      evt.stopPropagation()

      swipeStart = false
      offset.value = 0

      const delta = length - floor(prevLength.value)
      const absLength = abs(length)
      const swipeRate = absLength / VIEW_LENGTH
      const velocity = abs(getVelocity())
      reset()

      if (velocity > velocityThreshold || absLength >= VIEW_LENGTH / 2) {
        // 往前滑
        if ((dir === 'down' || dir === 'right') && length < 0 && delta < 0 && !isBlockBackward()) {
          onBackward && onBackward()
          setTransDur(1 - swipeRate)
        }

        // 往後滑
        else if ((dir === 'up' || dir === 'left') && length > 0 && delta > 0 && !isBlockForward()) {
          onForward && onForward()
          setTransDur(1 - swipeRate)
        }

        // 滑動切換沒觸發成功
        else {
          onRevert && onRevert()
          setTransDur()
        }
      }

      // 滑動切換沒觸發成功
      else {
        onRevert && onRevert()
        setTransDur()
      }
    },
  })
  const prevLength = usePrevious(isVertical ? lengthY : lengthX)

  return {
    offset: readonly(offset),
    swiping,
    transitionDuration: readonly(transitionDuration),
    resetTransitionDuration: () => {
      setTransDur()
    },
  }
}
